package com.tinem.platform.module.starter.web.config;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson.JSON;
import com.tinem.platform.module.pojo.co.GatewayHeadName;
import com.tinem.platform.module.pojo.co.RedisKeyEnum;
import com.tinem.platform.module.pojo.vo.error.SystemException;
import com.tinem.platform.module.starter.sdk.MessageCode;
import com.tinem.platform.module.starter.web.context.GatewayContext;
import feign.FeignException;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.Response;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author fengzhihao
 * @version v1
 * @program: platform
 * @className FeignConfiguration
 * @description TODO
 * @site 
 * @company 
 * @create 2020-07-12 18:33
 */
@Slf4j
@Configuration
public class FeignConfiguration implements RequestInterceptor, Decoder {

    public static final ThreadLocal<Map<String,String>> REQUEST_HEAD_LOCAL = new ThreadLocal<>();

    public static void setClientId(String clientId){
        String gatewayRequestId = UUID.randomUUID().toString();
        Map<String,String> requestHead = new HashMap<>();
        requestHead.put(GatewayHeadName.X_PLATFORM_GATEWAY_REQUEST_ID,gatewayRequestId);
        requestHead.put("clientId",clientId);
        REQUEST_HEAD_LOCAL.set(requestHead);
    }

    @Resource
    public StringRedisTemplate stringRedisTemplate;

    @Override
    public void apply(RequestTemplate template) {
        Map<String,String> requestHead = REQUEST_HEAD_LOCAL.get();
        if(requestHead != null){
            String key = RedisKeyEnum.gateway_req_info.getKey(requestHead.get(GatewayHeadName.X_PLATFORM_GATEWAY_REQUEST_ID));
            stringRedisTemplate.opsForHash().put(key, GatewayHeadName.X_PLATFORM_GATEWAY_CONTEXT_CLIENT_ID,requestHead.get("clientId"));
            stringRedisTemplate.expire(key,10, TimeUnit.MINUTES);
        }else {
            HttpServletRequest request = GatewayContext.getRequest();
            if(request == null){
                requestHead = new HashMap(){{
                    put(GatewayHeadName.X_PLATFORM_GATEWAY_REQUEST_ID, UUID.randomUUID().toString());
                    put(GatewayHeadName.X_PLATFORM_GATEWAY_REQ_LANG, Locale.CHINESE.getLanguage());
                }};;
            }else {
                requestHead = new HashMap<>();
                Enumeration enumeration = request.getHeaderNames();
                while (enumeration.hasMoreElements()){
                    String name	=(String) enumeration.nextElement();
                    if(!name.startsWith("x-platform-")){
                        continue;
                    }
                    String value = request.getHeader(name);
                    requestHead.put(name,value);
                }
            }
        }
        if(requestHead.get(GatewayHeadName.X_PLATFORM_GATEWAY_REQUEST_ID) == null){
            requestHead.put(GatewayHeadName.X_PLATFORM_GATEWAY_REQUEST_ID,UUID.randomUUID().toString());
        }
        requestHead.entrySet().forEach(e->{
            template.header(e.getKey(),e.getValue());
        });
        log.debug("feign client req url:{},gateway request id:{}",template.url(),template.headers().get(GatewayHeadName.X_PLATFORM_GATEWAY_REQUEST_ID).stream().findFirst().get());
    }

    @Override
    public Object decode(Response response, Type type) throws IOException, FeignException {
        String requestId = response.request().headers().get(GatewayHeadName.X_PLATFORM_GATEWAY_REQUEST_ID).stream().findFirst().get();
        log.debug("feign client req url:{},gateway request id:{}",response.request().url(),requestId);
        String body = IoUtil.read(response.body().asInputStream(),"UTF-8");
        if(response.status() != HttpStatus.OK.value()){
            log.error("feign client http status:{}, error:{} ",response.status(),body);
            throw new SystemException(MessageCode.ERROR_COMMONS_UNKNOWN);
        }
        if(response.headers().get(GatewayHeadName.X_PLATFORM_RES_CODE) == null){
            throw new SystemException(MessageCode.ERROR_COMMONS_UNKNOWN);
        }
        String code = response.headers().get(GatewayHeadName.X_PLATFORM_RES_CODE).stream().findFirst().get();
        String message = response.headers().get(GatewayHeadName.X_PLATFORM_RES_MESSAGE) == null?"":response.headers().get(GatewayHeadName.X_PLATFORM_RES_MESSAGE).stream().findFirst().get();

        if(!MessageCode.SUCCESS.name().equals(code)){
            message = Base64.decodeStr(message);
            log.error("feign client code:{}, message:{} error:{}",code,message,body);
            throw new SystemException(MessageCode.valueOf(code));
        }
        return JSON.parseObject(body,type);
    }
}
